package ch03.backtrack;


public class BacktrackParser extends Parser{
    public BacktrackParser(Lexer lexer) {
        super(lexer);
    }

    /** stat : list EOF | assign EOF ; */
    public void stat() throws RecognitionException, MismatchedTokenException {
        // 尝试解析选项1：list EOF
        if (speculate_stat_alt1()) {
            list();
            match(Lexer.EOF_TYPE);
        }
        // 尝试解析选项2：assign EOF
        else if (speculate_stat_alt2()) {
            assign();
            match(Lexer.EOF_TYPE);
        }
        // 肯定出错了，两个都不匹配，下面的LT(1)表示第一个向前看符号
        else {
            throw new NoViableAltException("expecting stat found " + LT(1));
        }
    }

    public boolean speculate_stat_alt1() {
        boolean success = true;
        mark();                         // 标记当前位置以便放回输入
        try {
            list();
            match(Lexer.EOF_TYPE);
        } catch (RecognitionException e) {
            success = false;
        }
        release();                      // 不管是否成功匹配到，都要放回输入（将消费掉的Token放回去）
        return success;
    }

    public boolean speculate_stat_alt2() {
        boolean success = true;
        mark();                         // 标记当前位置以便放回输入
        try {
            assign();
            match(Lexer.EOF_TYPE);
        } catch (RecognitionException e) {
            success = false;
        }
        release();                      // 不管是否匹配，都要放回输入
        return success;
    }


    /** assign : list '=' list ; // parallel assignment ;  */
    public void assign() throws RecognitionException {
        list();
        match(BacktrackLexer.EQUALS);
        list();
    }

    /** list : '[' elements ']' ; // match bracketed list */
    public void list() throws MismatchedTokenException, NoViableAltException {
        match(BacktrackLexer.LBRACK);
        elements();
        match(BacktrackLexer.RBRACK);
    }

    public void elements() throws MismatchedTokenException, NoViableAltException {
        element();
        while (LA(1) == BacktrackLexer.COMMA) {
            match(BacktrackLexer.COMMA);
            element();
        }
    }

    public void element() throws MismatchedTokenException, NoViableAltException {
        if (LA(1) == BacktrackLexer.NAME && LA(2) == BacktrackLexer.EQUALS) {
            match(BacktrackLexer.NAME);
            match(BacktrackLexer.EQUALS);
            match(BacktrackLexer.NAME);
        } else if (LA(1) == BacktrackLexer.NAME) {
            match(BacktrackLexer.NAME);
        } else if (LA(1) == BacktrackLexer.LBRACK) {
            list();
        } else {
            throw new NoViableAltException("expecting element found " + LT(1));
        }
    }
}
